﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Drawing;
using System.IO;

namespace ElemenTable
{
    public class TableManager
    {
        public List<ChemElement> TableElements { get; private set; }
        public Dictionary<string, Color> CurrentColor { get; private set; }
        public Dictionary<string, Color> GroupColor { get; private set; }
        public Dictionary<string, Color> StateColor { get; private set; }
        public Dictionary<string, Color> TypeColor { get; private set; }
        public DateTime Date { get; private set; }

        public TableManager()
        {
            TableElements = new List<ChemElement>();
            GroupColor = new Dictionary<string, Color>()
            {
                {Properties.Resources.Alkali_metal, Color.LightGreen},
                {Properties.Resources.Alkaline_earth_metal, Color.LightSeaGreen},
                {Properties.Resources.Noble_gas, Color.Khaki},
                {Properties.Resources.Halogen, Color.Orange},
                {Properties.Resources.Nonmetal, Color.OrangeRed},
                {Properties.Resources.Metalloid, Color.MediumOrchid},
                {Properties.Resources.Post_transition_metal, Color.Violet},
                {Properties.Resources.Transition_metal, Color.CornflowerBlue},
                {Properties.Resources.Lanthanoid, Color.LightSkyBlue},
                {Properties.Resources.Actinoid, Color.LightBlue},
            };
            StateColor = new Dictionary<string, Color>()
            {
                {"Solid", Color.FromArgb(160,160,160)},
                {"Liquid", Color.DodgerBlue },
                {"Gas", Color.YellowGreen }
            };
            TypeColor = new Dictionary<string, Color>()
            {
                {"Stable", Color.PaleGreen },
                {"Radioactive", Color.Yellow },
                {"Synthetic", Color.PaleVioletRed }
            };
            CurrentColor = GroupColor;
        }

        public void SetColorDesign(int number)
        {
            if (number == 2)
                CurrentColor = TypeColor;
            else if (number == 1)
                CurrentColor = StateColor;
            else
                CurrentColor = GroupColor;
        }

        public Color GetCurrentColor(ChemElement elem)
        {
            if (CurrentColor == StateColor)
                return StateColor[elem.State.ToString()];
            else if (CurrentColor == TypeColor)
                return TypeColor[elem.Attribute.ToString()];
            else
                return GroupColor[elem.GroupName];
        }

        public void LoadTable()
        {
            Stream file = typeof(TableManager).Assembly.GetManifestResourceStream("ElemenTable.Data.ElementData.xml");
            read_Table(file);
            string cult = System.Globalization.CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
            file = typeof(TableManager).Assembly.GetManifestResourceStream("ElemenTable.Data.ElementData_" + cult  + ".xml");
            if (file != null)
                read_Table(file, true);
        }

        private void read_Table(Stream file, bool reload = false)
        {
            using (XmlReader reader = XmlReader.Create(file))
            {
                reader.ReadToFollowing("periodic");
                if (reader.HasAttributes)
                {
                    reader.MoveToFirstAttribute();
                    Date = DateTime.Parse(reader.Value, new System.Globalization.CultureInfo("de"));
                }
                while (reader.ReadToFollowing("group"))
                {
                    string groupname = "";
                    if (reader.HasAttributes)
                    {
                        reader.MoveToFirstAttribute();
                        groupname = reader.Value;
                    }
                    reader.MoveToElement();
                    XmlReader groupreader = reader.ReadSubtree();
                    read_Group(ref groupreader, groupname, reload);
                }
            }
        }

        private void read_Group(ref XmlReader reader, string groupname, bool reload)
        {
            while (reader.ReadToFollowing("element"))
            {
                if (reader.HasAttributes)
                {
                    string symbol="", name="", phase="", config="", description="", oxnum="", attribute="";
                    int number=0, groupnum=0, period=0;
                    double mass = double.NaN, en = double.NaN, mpoint=double.NaN , bpoint=double.NaN;
                    System.Globalization.CultureInfo c = System.Globalization.CultureInfo.InvariantCulture;
                    while (reader.MoveToNextAttribute())
                    {
                        switch(reader.Name)
                        {
                            case "number":
                                number = Convert.ToInt32(reader.Value);
                                break;
                            case "symbol":
                                symbol = reader.Value;
                                break;
                            case "name":
                                name = reader.Value;
                                break;
                            case "group":
                                int.TryParse(reader.Value, out groupnum);
                                break;
                            case "period":
                                period = Convert.ToInt32(reader.Value);
                                break;
                            case "mass":
                                mass = double.Parse(reader.Value, c);
                                break;
                            case "en":
                                double ennum;
                                if (double.TryParse(reader.Value, System.Globalization.NumberStyles.Float, c, out ennum)) en = ennum; 
                                break;
                            case "oxnumbers":
                                oxnum = reader.Value;
                                break;
                            case "phase":
                                phase = reader.Value;
                                break;
                            case "mpoint":
                                if (double.TryParse(reader.Value,System.Globalization.NumberStyles.Float ,c, out ennum)) mpoint = ennum;
                                break;
                            case "bpoint":
                                if (double.TryParse(reader.Value, System.Globalization.NumberStyles.Float, c, out ennum)) bpoint = ennum;
                                break;
                            case "config":
                                config = reader.Value;
                                break;
                            case "attribute":
                                attribute = reader.Value;
                                break;
                            case "description":
                                description = reader.Value;
                                break;
                        }
                    }
                    if (reload)
                    {
                        ChemElement elem = (from elm in TableElements where elm.Number == number select elm).First();
                        elem.GroupName = groupname;
                        if (name != "") elem.Name = name;
                        elem.Description = description;
                    }
                    else
                    {
                        ChemElement elem = new ChemElement(groupname, number, symbol, name, mass, en);
                        if (groupnum != 0) elem.GroupNumber = groupnum;
                        if (period != 0) elem.PeriodNumber = period;
                        if (phase != "")
                        {
                            string text = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(phase);
                            elem.State = (ElementState)Enum.Parse(typeof(ElementState), text);
                        }
                        elem.MeltingPoint = mpoint;
                        elem.BoilingPoint = bpoint;
                        if (config != "") elem.Configuration = config;
                        if (attribute != "")
                        {
                            string text = System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(attribute);
                            elem.Attribute = (ElementType)Enum.Parse(typeof(ElementType), text);
                        }
                        if (description != "") elem.Description = description;
                        if (oxnum != "") elem.OxidationNumbers = Array.ConvertAll(oxnum.Split(','), int.Parse);
                        TableElements.Add(elem);
                    }
                }
            }
            reader.Close();
        }
    }
}
